/**
 * fetch数据请求类
 *  必须参数,在构造时传入
 *      url：请求路径，
 *      param：请求参数，这两个参数值，需要在new对象的时候创建，如:new Common(url,param)
 *      _type:请求返回值类型，如果在构造时没传，则默认为json
 *  可配置参数：
 *      inCookie：是否上送数据时包含cookie
 *      isTimeoutFetch：是否开启超时请求控制
 *      requestTimeOut：设置超时请求上限时间，如果不设置默认10000ms;number类型
 *      _postHeaders:设置默认的post请求headers
 *
 */
export default class Common{

    //函数入口-构造方法
    constructor(_url, _param, _type){
        // 请求接口路径
        this._url = _url;
        // 请求参数对象
        this._param = _param;
        // 请求返回值类型
        this._type = _type ? _type : "json";
        // 创建请求数据参数对象载体
        this.fetchSecParams = {};

        /************ 设置默认参数 - start  *******/
        // 设置默认包含上送cookie值标记
        this.inCookie = true;
        // 设置默认开启超时请求控制
        this.isTimeoutFetch = false;
        // 设置默认超时请求上限时间isTimeoutFetch属性为true时使用
        this.requestTimeOut = 10000;
        // 设置默认的post请求headers；
        this._postHeaders = {
            'Accept': 'application/json, text/javascript, */*; q=0.01',
            'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
        };

        /************ 设置默认参数 - end  *******/

        // 方法
        this.constFn();
    }

    /**
     * 构造方法集合
     */
    constFn(){
        /**
         * 请求超时处理方法，使用race方法判断返回；
         * 超时并未阻断请求，不会被丢弃掉，而是在后台继续运行，只是将本次返回后的相应内容丢弃；
         * 该方法内部处理不需要暴露在外
         * @param fetchPromise
         * @returns {Promise<R>|Promise.<*>}
         */
        this.timeoutFetch=(fetchPromise)=>{
            // 是否开启超时请求
            if ( this.isTimeoutFetch ){
                let timeFn = null;
                let timePromiseFn = new Promise((resolve,reject)=>{
                    timeFn = ()=>{
                        reject({status:0,message:"达到设置的请求超时上限"});
                    }
                });
                setTimeout(()=>{
                    timeFn();
                },this.requestTimeOut);
                return Promise.race([timePromiseFn,fetchPromise]);
            }else{
                return fetchPromise
            }
        };
        /**
         * get请求封装方法
         * 请求参数通过this.dealParam()方法处理后拼装至url路劲后面
         *
         */
        this.GetRequest=()=>{
            // 判断处理请求参数；
            if ( this._param ){
                this._url += "?" + this.dealParam();
                // 添加随机数
                this._url += "&random_num=" + this.createRandomNum();
            }
            // 判断是否包含cookie,如果包含配置credentials属性
            if ( this.inCookie ){
                this.fetchSecParams.credentials = 'include';
            }
            // 配置请求方式
            this.fetchSecParams.method = "GET";
            return new Promise((resolve, reject)=>{
                this.timeoutFetch(fetch(this._url,this.fetchSecParams)).then(resolve=>{
                    if (resolve.ok) {
                        return this.dealDataByType(resolve);
                    } else {
                        reject ({
                            status:resolve.status,
                            message:resolve.message?resolve.message:resolve.status
                        });
                    }
                }).then(response=>{
                    resolve(response);
                }).catch(error=>{
                    reject({
                        success:false,
                        status:error.status,
                        message:error.message?error.message:error.status
                    });
                });
            });
        };

        /**
         * post 请求方法封装
         * @constructor
         */
        this.PostRequest=()=>{
            let _header = new Headers(this._postHeaders);
            // 判断是否包含cookie,如果包含配置credentials属性
            if ( this.inCookie ){
                this.fetchSecParams.credentials = 'include';
            }
            // 请求方式
            this.fetchSecParams.method = "POST";
            // Content-Type配置方案
            this.fetchSecParams.headers = _header;
            // 请求参数数据
            this.fetchSecParams.body = this.dealParamByPost();
            return new Promise((resolve, reject)=>{
                this.timeoutFetch(fetch(this._url,this.fetchSecParams)).then(resolve=>{
                    if (resolve.ok) {
                        return this.dealDataByType(resolve);
                    } else {
                        reject ({
                            status:resolve.status,
                            message:resolve.message?resolve.message:resolve.status
                        });
                    }
                }).then(response=>{
                    resolve(response);
                }).catch(error=>{
                    reject({
                        success:false,
                        status:error.status,
                        message:error.message?error.message:error.status
                    });
                });
            });
        };

        /**
         * 根据_type处理接口返回的resolve数据，并返回需要的数据结构
         * @param resolve
         * @returns {*}
         */
        this.dealDataByType=(resolve)=>{
            let _data = null;
            switch (this._type){
                case "json":
                    _data = resolve.json();
                    break;
                case "text":
                    _data = resolve.text();
                    break;
                case "blob":
                    _data = resolve.blob();
                    break;
                case "formData":
                    _data = resolve.formData();
                    break;
            }
            return _data;
        };

        /**
         * 处理请求参数，最终以字符串并以‘&’符链接返回
         * 如："name=1&age=2"
         * @returns {string}
         */
        this.dealParam=()=>{
            let _arr = [];
            if ( this._param ){
                Object.keys(this._param).forEach((key,index)=>{
                    let _v = encodeURIComponent(this._param[key]);
                    _arr.push(key+"="+ _v);
                });
            }
            return _arr.join("&");
        };
        /**
         * 处理请求参数，最终以字符串并以‘&’符链接返回
         * 如："name=1&age=2"
         * @returns {string}
         */
        this.dealParamByPost=()=>{
            let _arr = [];
            if ( this._param ){
                Object.keys(this._param).forEach((key,index)=>{
                    // let _v = escape(this._param[key]);
                    let _v = encodeURIComponent(this._param[key]);
                    _arr.push(key+"="+ _v);

                });
            }
            return _arr.join("&");
        };

        /**
         * 创建随机数
         * @returns {number}
         */
        this.createRandomNum=()=>{
            let random_num = 0;
            for(let i=0;i<6;i++) {
                random_num+=Math.floor(Math.random()*100000);
            }
            return random_num;
        };
    }
}